package com.benmei.weike.web;

import com.benmei.weike.common.Constants;
import com.benmei.weike.common.GoodsCategory;
import com.benmei.weike.common.Lang;
import com.benmei.weike.common.PayType;
import com.benmei.weike.dto.wechatSmallProgram.CheckoutUserState;
import com.benmei.weike.dto.wechatSmallProgram.payment.CreateWeixinPayOrderRequest;
import com.benmei.weike.dto.wechatSmallProgram.payment.CreateWeixinPayOrderResponse;
import com.benmei.weike.dto.wechatSmallProgram.RegisterSmallProgramDto;
import com.benmei.weike.entity.WeiChatPayNotifyRequest;
import com.benmei.weike.exception.ClientException;
import com.benmei.weike.exception.ServerException;
import com.benmei.weike.service.PaymentService;
import com.benmei.weike.service.WechatSmallProgramService;
import com.benmei.weike.service.common.MemcachedService;
import com.benmei.weike.util.IPUtil;
import com.benmei.weike.util.JsonUtil;
import com.benmei.weike.util.Sms;
import com.benmei.weike.util.XmlUtil;
import com.nativetalk.base.RetInfo;
import com.nativetalk.bean.member.TdNtMember;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Map;

/**
 * Created by waijiaojun on 2017/11/2.
 */
@RestController
@RequestMapping(value = "/wechatSmallProgram")
public class StudentWechatSmallProgramController {
    private static Logger logger = LoggerFactory.getLogger(StudentWechatSmallProgramController.class);

    @Resource
    private WechatSmallProgramService wechatSmallProgramService;

    @Autowired
    private MemcachedService memcachedService;

    @Autowired
    private PaymentService paymentService;

    // 通过小程序中的code查询token
    @RequestMapping(value = "/getTokenByCode", method = {RequestMethod.GET})
    @ResponseBody
    public RetInfo getSmallProgramOpenId(HttpServletRequest request) {
        RetInfo retInfo = null;
        String code = request.getParameter("code");
        if (StringUtils.isBlank(code)) {
            return RetInfo.getClientErrorInfo("code不能为空");
        }
        try {
            Map<String, String> map = wechatSmallProgramService.getToken(code);
            retInfo = RetInfo.getSuccessInfo(map);
        } catch (ClientException e) {
            logger.error(e.getMessage(), e);
            retInfo = RetInfo.getClientErrorInfo(e.getCode(),e.getMessage());
            return retInfo;
        }catch (IOException e) {
            logger.error(e.getMessage(), e);
            retInfo = RetInfo.getServerErrorInfo("未获取到用户openID");
            return retInfo;
        }
        logger.info(Constants.prefix_out + JsonUtil.toJson(retInfo));
        return retInfo;
    }

    //用户在小程序上注册账号
    @RequestMapping(value = "/smallProgram/register", method = {RequestMethod.POST})
    @ResponseBody
    public RetInfo register(@RequestBody RegisterSmallProgramDto registerSmallProgramDto){
        RetInfo retInfo=new RetInfo();
        if(StringUtils.isBlank(registerSmallProgramDto.getMemberPhoneArea())){
            retInfo.setMark("-1");
            retInfo.setTip("phone area can not be null");
            return retInfo;
        }
        if(StringUtils.isBlank(registerSmallProgramDto.getMemberPhone())){
            retInfo.setMark("-1");
            retInfo.setTip("phone can not be null");
            return retInfo;
        }
        if(StringUtils.isBlank(registerSmallProgramDto.getMemberPassword())){
            retInfo.setMark("-1");
            retInfo.setTip("password can not be null");
            return retInfo;
        }
        try {
            Map<String,String> map=wechatSmallProgramService.getNewMemberToken(registerSmallProgramDto);
            if(StringUtils.isNotBlank(map.get("message"))){
                retInfo.setMark("-1");
                retInfo.setTip(map.get("message"));
                return retInfo;
            };
            retInfo.setMark("1");
            retInfo.setTip("注册成功");
            retInfo.setObj(map);
        }catch (ClientException e) {
           retInfo=RetInfo.getClientErrorInfo(e.getCode(),e.getMessage());
            return retInfo;
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
            retInfo = RetInfo.getServerErrorInfo("未获取到用户openID");
            return retInfo;
        }
        return retInfo;
    }

    // 小程序调用支付接口，使用余额或微信支付
    @RequestMapping(value = "/token/payment", method = {RequestMethod.POST})
    @ResponseBody
    public RetInfo payment(HttpServletRequest request, @RequestBody CreateWeixinPayOrderRequest req, @RequestHeader(value = "token") String token) {
        try {
            logger.info(Constants.prefix_in + JsonUtil.toJson(req));
            //校验token，如果校验通过就从缓存中读取Member
            if (StringUtils.isBlank(token)) {
                RetInfo retInfo = RetInfo.getClientErrorInfo("Parameter token  is required");
                logger.info(JsonUtil.toJson(retInfo));
                return retInfo;
            }
            Object o = memcachedService.get(token);
            if (o == null) {
                RetInfo retInfo = RetInfo.getReloginInfo(Lang.ZH);
                logger.info("缓存中没有MemberToken:[" + token + "]，用户需要重新登录系统。 retInfo-->" + JsonUtil.toJson(retInfo));
                return retInfo;
            }

            if (!TdNtMember.class.isInstance(o)) {
                RetInfo retInfo = RetInfo.getReloginInfo(Lang.ZH);
                logger.info("缓存的token不是TdNtMember类型:[" + token + "]，用户需要重新登录系统。 retInfo-->" + JsonUtil.toJson(retInfo));
                return retInfo;
            }
            TdNtMember tdNtMember = (TdNtMember) o;

            // 一 、商品类别相关校验
            if (StringUtils.isBlank(req.getGoodsCategoryCode())) {
                RetInfo retInfo = RetInfo.getClientErrorInfo("商品类别不能为空");
                logger.info(JsonUtil.toJson(retInfo) + "，goodsCategoryCode:" + req.getGoodsCategoryCode());
                return retInfo;
            }
            if (!GoodsCategory.contains(req.getGoodsCategoryCode())) {
                RetInfo retInfo = RetInfo.getClientErrorInfo("无效的商品类别");
                logger.info(JsonUtil.toJson(retInfo) + "，goodsCategoryCode:" + req.getGoodsCategoryCode());
                return retInfo;
            }

            // 充值
            if (GoodsCategory.RECHARGE.getCode().equals(req.getGoodsCategoryCode())) {

                // 1 充值金额必须大于0
                if (req.getMoney() == null || req.getMoney().compareTo(new BigDecimal(0)) <= 0) {
                    RetInfo retInfo = RetInfo.getClientErrorInfo("充值金额必须大于0");
                    logger.info(JsonUtil.toJson(retInfo) + "，money:" + req.getMoney());
                    return retInfo;
                }

                // 2 充值不能使用余额支付，不能使用混合支付
                if (PayType.WALLET.equals(req.getPayType()) || PayType.MULTIPLE.equals(req.getPayType())) {
                    RetInfo retInfo = RetInfo.getClientErrorInfo("充值必须使用第三方支付");
                    logger.info(JsonUtil.toJson(retInfo) + "，PayType:" + req.getPayType());
                    return retInfo;
                }
            }

            // 二、支付类型校验：wallet、multiple、thirdpart
            // 校验payType
            String payType = req.getPayType();
            if (StringUtils.isBlank(payType)) {
                RetInfo retInfo = RetInfo.getClientErrorInfo("支付类型不能为空");
                logger.info(JsonUtil.toJson(retInfo) + " payType:" + payType);
                return retInfo;
            }
            if (!PayType.contains(payType)) {
                RetInfo retInfo = RetInfo.getClientErrorInfo("无效的支付类型");
                logger.info(JsonUtil.toJson(retInfo) + " payType:" + payType);
                return retInfo;
            }

            // 如果是第三方支付或混合支付，那么支付渠道不能为空，并且不能随意写
            if (payType.equals(PayType.THIRDPART) || payType.equals(PayType.MULTIPLE)) {
                String payChannel = req.getChannel();
                if (StringUtils.isBlank(payChannel)) {
                    RetInfo retInfo = RetInfo.getClientErrorInfo("支付渠道不能为空");
                    logger.info(JsonUtil.toJson(retInfo) + " channel:" + payChannel);
                    return retInfo;
                }
                if (!payChannel.equals(Constants.PaymentChannel.wxpay_name)) {
                    RetInfo retInfo = RetInfo.getClientErrorInfo("支付渠道错误：支付渠道只能是wx");
                    logger.info(JsonUtil.toJson(retInfo) + " channel:" + payChannel);
                    return retInfo;
                }
            }

            CreateWeixinPayOrderResponse order = paymentService.studentCreateOrderForWeixinPay(req, tdNtMember.getMemb_id(), IPUtil.getIp(request));
            RetInfo retInfo = RetInfo.getSuccessInfo("订单创建成功");
            retInfo.setObj(order);
            logger.info(Constants.prefix_out + JsonUtil.toJson(retInfo));
            return retInfo;
        } catch (ClientException e) {
            logger.error(e.getMessage(), e);
            RetInfo retInfo = RetInfo.getClientErrorInfo(e.getMessage());
            logger.error(Constants.prefix_out + JsonUtil.toJson(retInfo));
            return retInfo;
        } catch (ServerException e) {
            logger.error(e.getMessage(), e);
            RetInfo retInfo = RetInfo.getServerErrorInfo(e.getMessage());
            logger.error(Constants.prefix_out + JsonUtil.toJson(retInfo));
            return retInfo;
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            RetInfo retInfo = RetInfo.getServerErrorInfo();
            logger.error(Constants.prefix_out + JsonUtil.toJson(retInfo));
            return retInfo;
        }
    }

    /**
     * @return RetInfo
     * @Purpose WeiXinPay异步通知
     * @version 1.0
     * @time 2017-11-23
     * @author Peter
     */
    @RequestMapping(value = "/WeiChatPay/notify", method = {RequestMethod.GET,RequestMethod.POST})
    @ResponseBody
    public String notify(@RequestBody(required = false) String params, HttpServletRequest request, HttpServletResponse response) {
        String result = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
        try {
            //打印入参
            logger.info("\nWeiXinPay WebHooks异步通知 -->>\n" + Constants.prefix_in + params);
            request.setCharacterEncoding("UTF8");

            WeiChatPayNotifyRequest notifyRequest = XmlUtil.fromXml(params,WeiChatPayNotifyRequest.class);
            notifyRequest.setNotify_body(params);
            paymentService.notifyForWeiChatPay(notifyRequest);

            logger.info(Constants.prefix_out +result);
            //打印出参
        } catch (Exception e) {
            //记录错误日志
            logger.error(e.getMessage(), e);
            //打印出参
            logger.error(Constants.prefix_out +result);
        }
        return result;
    }

    /**
     * 发送验证码
     * @param sms
     * @return
     */
    @RequestMapping(value="/sendMessage",method = {RequestMethod.POST}, consumes = "application/json; charset=utf-8")
    @ResponseBody
    public RetInfo sendMessage(@RequestBody Sms sms){
        try{
            //打印入参
            logger.info(Constants.prefix_out + JsonUtil.toJson(sms));
            RetInfo retInfo=new RetInfo();
            if(StringUtils.isBlank(sms.getMemb_phone())){
                retInfo.setMark("-1");
                retInfo.setTip("memb_phone cann't be null");
                return retInfo;
            }
            if(StringUtils.isBlank(sms.getMemb_phone_area())){
                retInfo.setMark("-1");
                retInfo.setTip("memb_phone_area cann't be null");
                return retInfo;
            }
            retInfo = wechatSmallProgramService.sendMessage(sms);
            //打印出参
            logger.info(Constants.prefix_out + JsonUtil.toJson(retInfo));
            return retInfo;
        }catch (Exception e){
            //记录错误日志
            RetInfo retInfo = RetInfo.getServerErrorInfo(Lang.ZH);
            logger.error(e.getMessage(), e);
            //打印出参
            logger.info(Constants.prefix_out + JsonUtil.toJson(retInfo));
            return retInfo;
        }
    }

    /**
     * 检查该用户为新老用户
     * 老用户则更新openid
     * @param checkoutUserState
     * @return
     */
    @RequestMapping(value="/checkUserState",method = {RequestMethod.POST})
    @ResponseBody
    public RetInfo CheckoutUser(@RequestBody CheckoutUserState checkoutUserState){
        try{
            //打印入参
            logger.info(Constants.prefix_in + JsonUtil.toJson(checkoutUserState));
            RetInfo retInfo=new RetInfo();
            //校验参数
            if(StringUtils.isBlank(checkoutUserState.getMemb_phone())){
                retInfo.setMark("-1");
                retInfo.setTip("手机号不能为空");
                return  retInfo;
            }
            if(StringUtils.isBlank(checkoutUserState.getMemb_phone_area())){
                retInfo.setMark("-1");
                retInfo.setTip("手机号国家代码不能为空");
                return  retInfo;
            }
            if(StringUtils.isBlank(checkoutUserState.getCode())){
                retInfo.setMark("-1");
                retInfo.setTip("验证码不能为空");
                return  retInfo;
            }
            if(StringUtils.isBlank(checkoutUserState.getJs_code())){
                retInfo.setMark("-1");
                retInfo.setTip("js_code 不能为空");
                return  retInfo;
            }
            retInfo=wechatSmallProgramService.checkoutUser(checkoutUserState);
            logger.info(Constants.prefix_out+JsonUtil.toJson(retInfo));
            return  retInfo;
        }catch (ClientException e) {
            RetInfo retInfo = RetInfo.getServerErrorInfo(Lang.ZH);
            retInfo=RetInfo.getClientErrorInfo(e.getCode(),e.getMessage());
            return retInfo;
        } catch (ServerException e) {
            RetInfo retInfo = RetInfo.getServerErrorInfo(Lang.ZH);
            retInfo=RetInfo.getServerErrorInfo(e.getCode(),e.getMessage());
            return retInfo;
        }catch (Exception e){
            //记录错误日志
            RetInfo retInfo = RetInfo.getServerErrorInfo(Lang.ZH);
            logger.error(e.getMessage(), e);
            logger.info(Constants.prefix_out+JsonUtil.toJson(retInfo));
            return  retInfo;
        }
    }
}

